﻿using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;

/// <summary>
/// 音频播放器。由于只使用了一个播放源，只适用于简单场景
/// </summary>
public class SoundManager : GameFrameClassBase
{
    private static string s_PlayingBGM = string.Empty;
    private static AudioSource s_BgmSource, s_EffectSource, s_VoiceSource;
    private static Dictionary<string, AudioClip> s_AudioClips = new Dictionary<string, AudioClip>();
    private static List<string> s_LoadingKeys = new List<string>();

    /// <summary>
    /// 全局
    /// </summary>
    public static float GlobalVolume
    {
        get => s_GlobalVolume;
        set
        {
            s_GlobalVolume = Mathf.Clamp01(value);
            s_EffectSource.volume = s_GlobalVolume;
            s_BgmSource.volume = s_GlobalVolume;
        }
    }
    private static float s_GlobalVolume = 1.0f;

    /// <summary>
    /// 背景音乐
    /// </summary>
    public static float bgmVolume
    {
        get => s_BgmVolume;
        set
        {
            s_BgmVolume = Mathf.Clamp01(value);
            s_BgmSource.volume = s_BgmVolume;
        }
    }
    private static float s_BgmVolume = 1.0f;

    /// <summary>
    /// 音效
    /// </summary>
    public static float effectVolume
    {
        get => s_EffectVolume;
        set
        {
            s_EffectVolume = Mathf.Clamp01(value);
            s_BgmSource.volume = s_EffectVolume;
        }
    }
    private static float s_EffectVolume = 1.0f;

    /// <summary>
    /// 语音
    /// </summary>
    public static float voiceVolume
    {
        get => s_VoiceVolume;
        set
        {
            s_VoiceVolume = Mathf.Clamp01(value);
            s_BgmSource.volume = s_VoiceVolume;
        }
    }
    private static float s_VoiceVolume = 1.0f;


    public override UniTask InitAsync()
    {
        GameObject go = new GameObject(nameof(SoundManager));
        s_BgmSource = go.AddComponent<AudioSource>();
        s_BgmSource.loop = true;
        s_EffectSource = go.AddComponent<AudioSource>();
        s_VoiceSource = go.AddComponent<AudioSource>();
        GameObject.DontDestroyOnLoad(s_EffectSource);
        return new UniTask();
    }

    public static async void PlayBGM(string soundKey)
    {
        var sound = await LoadClip(soundKey);
        PlayBGM(sound);
    }

    public static void PlayBGM(AudioClip sound)
    {
        s_BgmSource.Stop();
        s_BgmSource.clip = sound;
        s_PlayingBGM = sound.name;
        s_BgmSource.Play();
    }

    public static void PauseBGM()
    {
        s_BgmSource.Pause();
    }

    public static void UnpauseBGM()
    {
        s_BgmSource.UnPause();
    }

    public static void StopBGM()
    {
        s_BgmSource.Stop();
        s_PlayingBGM = string.Empty;
    }

    public static string GetPlayingBGM()
    {
        return s_PlayingBGM;
    }

    public static bool GetPlayingBGM(string soundKey)
    {
        if (!s_AudioClips.TryGetValue(soundKey, out var sound))
            return false;
        return IsPlayingBGM(sound);
    }

    public static bool IsPlayingBGM(AudioClip sound)
    {
        return s_BgmSource.clip == sound;
    }

    public static async void PlayEffect(string soundKey)
    {
        var sound = await LoadClip(soundKey);
        PlayEffect(sound);
    }

    public static void PlayEffect(AudioClip sound)
    {
        s_EffectSource.PlayOneShot(sound);
    }

    private static bool s_IsPlayingEffectAndPauseBGM = false;
    /// <summary>
    /// 播放音效并暂停BGM，音效播完时恢复BGM
    /// </summary>
    public static async void PlayEffectAndPauseBGM(string soundKey)
    {
        var sound = await LoadClip(soundKey);
        PlayEffectAndPauseBGM(sound);
    }

    /// <summary>
    /// 播放音效并暂停BGM，音效播完时恢复BGM
    /// </summary>
    public static async void PlayEffectAndPauseBGM(AudioClip sound)
    {
        if (s_IsPlayingEffectAndPauseBGM)
            return;
        if (s_BgmSource.isPlaying)
            PlayEffect(sound);
        s_IsPlayingEffectAndPauseBGM = true;
        PauseBGM();
        s_EffectSource.PlayOneShot(sound);
        await UniTask.WaitForSeconds(sound.length);
        UnpauseBGM();
        s_IsPlayingEffectAndPauseBGM = false;
    }

    /// <summary>
    /// 播放音效并在播完时播放BGM
    /// </summary>
    public static async void PlayEffectFollowBGM(string effectKey, string bgmKey)
    {
        var effect = await LoadClip(effectKey);
        var bgm = await LoadClip(bgmKey);
        PlayEffectFollowBGM(effect, bgm);
    }

    /// <summary>
    /// 播放音效并在播完时播放BGM
    /// </summary>
    public static async void PlayEffectFollowBGM(AudioClip effect, AudioClip bgm)
    {
        StopBGM();
        PlayEffect(effect);
        await UniTask.WaitForSeconds(effect.length);
        PlayBGM(bgm);
    }

    public static async void PlayVoice(string soundKey)
    {
        var sound = await LoadClip(soundKey);
        s_VoiceSource.PlayOneShot(sound);
    }

    private static async UniTask<AudioClip> LoadClip(string soundKey)
    {
        if (s_LoadingKeys.Contains(soundKey))
            await UniTask.WaitUntil(() => s_LoadingKeys.Contains(soundKey));
        if (!s_AudioClips.TryGetValue(soundKey, out var sound))
        {
            s_LoadingKeys.Add(soundKey);
            sound = await Addressables.LoadAssetAsync<AudioClip>(soundKey);
            s_AudioClips.Add(soundKey, sound);
            s_LoadingKeys.Remove(soundKey);
        }
        return sound;
    }
}